;------------------------------------------------------------------------------
; Versija: 0.5
; 2009-04-28
;
; loader.asm - Operacines sistemos "Crazy Monkey" loader'is.
;
; Dokumentacija:
;   ---
;
; Loader'is EXT2 failu sistemoje susiranda kernel kataloga (kuris turi buti
; antrasis katalogas, sukurtas failu sistemoje), jame suranda transmigration
; faila, kuris yra kraunamos sistemos reinkarnacijos valdytojas, atsakingas
; uz visos likusios sistemos uzkrovimo i atminti ir jos paleidima (sis
; failas turi buti antras failas, sukurtas failu sistemoje). Pries paleidziant
; reinkarnacijos valdytoja uzkraunama laikina GDT, pereinama i A20 Mode,
; isjungimas NMI ir pereinama i 32-bit mode.
; transmigration failas yra uzkraunamas RAM atmintyje 0x100000 adresu.
;
; Pastaba:
;   kernel katalogo ir transmigration failo sukurimo tvarka yra svarbi siekiant
;   supaprastinti loader'io struktura.
;
;   ---
;
;   ;------------------------------------------------
;   ; (proceduros aprasas)
;   ;
;   ; Cng reg: (keiciami registrai)
;   ; In: (proceduros parametrai)
;   ; Out: (proceduros rezultatai)
;   ; Err: (klaidos salyga ir rezultatas)
;   ;------------------------------------------------
;------------------------------------------------------------------------------

;----------
; Antraste
;----------

[bits 16]    ; 16-bit programos kodas.
[org 0x500]  ; Programos kodo adresas atmintyje (0x0050:0x0000).

;----------
; Kodas
;----------

;------------------------------------------------
; Pagrindine loader'io procedura.
;------------------------------------------------
main:

  ; Nusistatome segmentus.
  cli
  xor ax, ax
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  sti
  
  mov [boot_drive], dl  ; Issisaugome irenginio is kurio kraunamasi koda.
  
  mov si, stringStage   ; I SI ikrauname eilutes pradzios adresa.
  call printString      ; Kvieciame eilutes spausdinimo procedura.

;------------------------------------------------

  reset:

    mov ah, 0x00          ; Irenginio atstatymo pertraukimas.
    mov dl, [boot_drive]  ; Irenginys, kuri atstatinesime.
    int 0x13              ; Pertraukimas.
    jc reset              ; Jeigu buvo klaida - bandome dar karta.

;------------------------------------------------

  ; Nuskaitome SuperBlock pirma sektoriu (512 baitu).
  mov byte [sector_number], 0x03  ; Treciame sektoriuje yra SuperBlock.
  call readSector
  
  ; Issisaugome bloko dydi.
  mov ax, 0x0018            ; 0x0018 offset'u prasideda bloko dydzio irasas.
  mov bx, block_size
  call read4Bytes

  ; Issisaugome bloku skaiciu grupeje.
  mov ax, 0x0020            ; 0x0020 offset'u prasideda irasas.
  mov bx, blocks_per_group
  call read4Bytes

  ; Issisaugome inode skaiciu grupeje.
  mov ax, 0x0028            ; 0x0028 offset'u prasideda irasas.
  mov bx, inodes_per_group
  call read4Bytes

  ; Skaiciuojame bloko dydi.
  mov ax, 0x0400                  ; Darysime 1024 (0x0400) shift left.
  mov cl, byte [block_size+0x03]
  shl ax, cl                      ; Darome shift left.
  mov word [block_size+0x02], ax

;------------------------------------------------
  
  ; Nuskaitome Group Descriptor Table bloka (512 baitu).
  mov byte [sector_number], 0x05  ; Penktame sektoriuje yra GDT.
  call readSector

  ; Issisaugome inode lenteles bloko numeri.
  mov ax, 0x0008                  ; 0x0008 offset'u prasideda irasas.
  mov bx, inode_table
  call read4Bytes

  ; Nuskaitome Inode Table bloka (512 baitu).
  mov ax, word [inode_table+0x02]
  call readBlock

  ; Issisaugome root pirmo bloko numeri.
  mov ax, 0x00a8        ; Imsime Inode 2 informacija (0x80 + 0x28 offset).
  mov bx, tmp_dd
  call read4Bytes

  ; Nuskaitome root pirma bloka (512 baitu).
  mov ax, word [tmp_dd+0x02]
  call readBlock

;------------------------------------------------

  ; Issisaugome kernel katalogo inode bloko numeri.
  mov ax, 0x0050        ; 0x0004 offset'u prasideda bloko numeris.
  call tmpProcedure
  
  ; Issaugome kernel katalogo pirmo bloko numeri.
  mov ax, word [tmp_dd+0x02]
  sub ax, 0x0001
  mov bx, 0x0080        ; Vienas inode irasas uzima 0x0080 baitu.
  mul bx
  add ax, 0x0028        ; 0x0028 offset'u prasideda adresai i atminties blokus.
  mov bx, tmp_dd
  call read4Bytes

  ; Nuskaitome kernel katalogo pirma bloka (512 baitu).
  mov ax, word [tmp_dd+0x02]
  mov byte [number_of_sectors], 0x01
  call readBlock

;------------------------------------------------

  ; Issisaugome kernel'io failo inode bloko numeri.
  mov ax, 0x0018        ; 0x0008 offset'u prasideda irasas.
  call tmpProcedure
  
  ; Issisaugome kernel'io failo dydi.
  mov ax, word [tmp_dd+0x02]
  sub ax, 0x0001
  mov bx, 0x0080        ; Vienas inode irasas uzima 0x0080 baitu.
  mul bx
  add ax, 0x0004        ; 0x0028 offset'u prasideda failo dydzio irasas.
  mov bx, kernel_size
  call read4Bytes

;------------------------------------------------
	
  ; Paskaiciuojame kiek bloku uzima kernel'io failas.
  xor ax, ax
  xor bx, bx
  mov ax, word [kernel_size+0x02]
  mov bx, word [block_size+0x02]
  div bx
  mov cx, ax
  cmp dx, 0x0000
  jz wasNull
  add cx, 0x0001
  wasNull:
  xor ax, ax
  xor bx, bx
  mov ax, word [kernel_size]
  mov bx, 0x0040
  mul bx
  add cx, ax
  mov word [block_no], cx
  
  xor bx, bx
  
  ; Ciklas nuskaitantis visus kernel failo blokus.
  readKernelBlocks:
  
    inc bx
    cmp bx, 0x000d
    je level2
    push bx
    push cx   ; Issisaugome ciklo skaitliuka.
    
    ; Pereiname i atminties vieta kur yra nuskaityta informacija.
    mov ax, 0x1000
    mov es, ax
    
    ; Issivalome registrus.
    xor ax, ax
    xor bx, bx
    
    ; Issaugome kernel'io failo bloko numeri.
    mov ax, word [tmp_dd+0x02]
    sub ax, 0x0001
    mov bx, 0x0080        ; Vienas inode irasas uzima 0x0080 baitu.
    mul bx
    add ax, word [offset_of]
    mov bx, kernel_block
    call read4Bytes
    
    ; Pereiname i atminties vieta kur issaugosime kernel'i.
    mov ax, 0x2000
    mov word [sector_to], ax
    
    ; Nuskaitome kernel'io failo bloka (512 baitu).
    mov ax, word [kernel_block+0x02]
    mov byte [number_of_sectors], 0x02
    call readBlock
    
    ; Offset kur rasysime kita kernel'io failo bloka.
    xor ax, ax
    mov ax, word [read_to]
    add ax, word [block_size+0x02]
    mov word [read_to], ax
    
    ; Kito kernel'io failo bloko offset.
    xor ax, ax
    mov ax, word [offset_of]
    add ax, 0x0004        ; Adreso ilgis yra 0x0004 baitai.
    mov word [offset_of], ax
    
    pop cx
    pop bx
  
  loop readKernelBlocks
  
  level2:

    push cx
    
    ; Pereiname i atminties vieta kur yra nuskaityta informacija.
    mov ax, 0x1000
    mov es, ax
    
    ; Issivalome registrus.
    xor ax, ax
    xor bx, bx
    
    ; Issaugome kernel'io failo bloko numeri.
    mov ax, word [tmp_dd+0x02]
    sub ax, 0x0001
    mov bx, 0x0080        ; Vienas inode irasas uzima 0x0080 baitu.
    mul bx
    add ax, word [offset_of]
    mov bx, block_13
    call read4Bytes
    
    ; Kito kernel'io failo bloko offset.
    xor ax, ax
    mov ax, word [offset_of]
    add ax, 0x0004        ; Adreso ilgis yra 0x0004 baitai.
    mov word [offset_of], ax
    
    ; Issaugome kernel'io failo bloko numeri.
    mov ax, word [tmp_dd+0x02]
    sub ax, 0x0001
    mov bx, 0x0080        ; Vienas inode irasas uzima 0x0080 baitu.
    mul bx
    add ax, word [offset_of]
    mov bx, block_14
    call read4Bytes
    
    ; Issisaugome kernel'io failo irasymo offset.
    xor ax, ax
    mov word [offset_of], ax

    ; Nusistatome segmenta, kur rasysime lentele.
    mov ax, 0x1000
    mov word [sector_to], ax
    
    ; Nusistatome offset, kur rasysime lentele.
    mov ax, word [read_to]
    mov word [read_to], 0x0000
    push ax
    
    ; Nuskaitome EXT2 pirmo lygio netiesiogine bloku nuorodu lentele.
    mov ax, word [block_13+0x02]
    mov byte [number_of_sectors], 0x02
    call readBlock
    
    pop ax
    mov word [read_to], ax

    pop cx

    xor bx, bx
    readKernelBlocks2:
    
      inc bx
      cmp bx, 0x0101
      je level3
      push bx
      push cx
      
      ; Pereiname i atminties vieta kur yra nuskaityta informacija.
      mov ax, 0x1000
      mov es, ax
      
      ; Issivalome registrus.
      xor ax, ax
      xor bx, bx
      
      ; Issaugome kernel'io failo bloko numeri.
      add ax, word [offset_of]
      mov bx, kernel_block
      call read4Bytes
      
      ; Pereiname i atminties vieta kur issaugosime kernel'i.
      mov ax, 0x2000
      mov word [sector_to], ax
      
      ; Nuskaitome kernel'io failo bloka (512 baitu).
      mov ax, word [kernel_block+0x02]
      mov byte [number_of_sectors], 0x02
      call readBlock
      
      ; Offset kur rasysime kita kernel'io failo bloka.
      xor ax, ax
      mov ax, word [read_to]
      add ax, word [block_size+0x02]
      mov word [read_to], ax
      
      ; Kito kernel'io failo bloko offset.
      xor ax, ax
      mov ax, word [offset_of]
      add ax, 0x0004        ; Adreso ilgis yra 0x0004 baitai.
      mov word [offset_of], ax
      
      pop cx
      pop bx

    loop readKernelBlocks2
  
  ; Nereikalinga kol kernel'io failas neperzengia 20K dydzio.
  level3:
  ; To Do

;------------------------------------------------

  mov si, stringStack   ; I SI ikrauname eilutes pradzios adresa.
  call printString      ; Kvieciame eilutes spausdinimo procedura.
  
  ; Sukuriame steka (0x9000-0xffff).
  cli
  mov ax, 0x9000
  mov ss, ax
  mov sp, 0xffff
  sti

  mov si, stringGDT     ; I SI ikrauname eilutes pradzios adresa.
  call printString      ; Kvieciame eilutes spausdinimo procedura.
  
  ; Uzkrauname GDT.
  cli
  pusha
  lgdt [toc]
  popa
  sti
  
  mov si, stringA20     ; I SI ikrauname eilutes pradzios adresa.
  call printString      ; Kvieciame eilutes spausdinimo procedura.
  
  ; Ijungiame A20 Mode.
  pusha
  xor ax, ax
  mov ax, 0x2401
  int 0x15
  popa
  
  mov si, stringNMI     ; I SI ikrauname eilutes pradzios adresa.
  call printString      ; Kvieciame eilutes spausdinimo procedura.

  ; Isjungiame NMI.
  xor ax, ax
  mov al, 0x80
  out 0x70, al
  in al, 0x71

  mov si, stringPMode   ; I SI ikrauname eilutes pradzios adresa.
  call printString      ; Kvieciame eilutes spausdinimo procedura.

  ; Pereiname i Protected Mode.
  xor eax, eax
  cli
  mov eax, cr0
  or al, 0x01
  mov cr0, eax

  ; Persokame i Protected Mode (pakeiciame CS registra atitinkamai, pagal GDT).
  push word 0x0008
  push word Stage3
  retf
  
;------------------------------------------------
; prt:

  ; mov ax, 0x0000
  ; mov si, ax
  ; mov ax, 0x1000
  ; mov es, ax

  ; xor bx, bx
  ; xor cx, cx
  ; mov cx, 0x0004
  
  ; ciklas:
   
    ; push bx
    ; push cx
    ; mov al, [block_size+bx]
    ; call printHEX
    ; pop cx
    ; pop bx
    ; inc bx
    
  ; loop ciklas
;------------------------------------------------

  ; jmp $                 ; Amzinas ciklas
  
;------------------------------------------------
; Procedura atspausdinanti HEX simbolius.
;
; Cng reg: AX, BX, CX, DX
; In: AL
; Out: Atspausdintas HEX
;------------------------------------------------
; printHEX:

  ; xor ah, ah          ; Registru isvalymas

  ; mov cl, 0x2         ; Kiek simboliu reikes atspausdinti.
  ; mov dl, 0x10        ; Daliklis.
  ; div dl              ; Atskiriame dalmeni ir liekana.

  ; mov [tmp], ah       ; Laikinai issisaugome registro reiksme.

  ; jmp spausdinimas    ; Spausdinsime pirma simboli.

  ; tesinys:            ; Spausdinsime antra simboli.

    ; xor ah, ah        ; Registru isvalymas
    ; mov al, [tmp]     ; Kitas simbolis kuri reikia atspausdinti.

  ; spausdinimas:

    ; cmp al, 0x0a      ; Tikriname ar AL registre yra skaicius ar raide.
    ; jc skaicius
    ; jnc raide

    ; skaicius:         ; Jei skaicius.

      ; add al, 0x30    ; Pridedame 0x30, kad gautume ASCII simboli.
      ; call printChar  ; Kvieciame simbolio spausdinimo procedura.
      ; dec cl          ; Viena simboli atspausdinome, todel sumaziname skaitliuka.
      ; cmp cl, 0x00    ; Tikriname ar du simboliai atspausdinti.
      ; je pabaiga      ; Jei taip, tai baigiame proceduros darba.
      ; jmp tesinys     ; Jei ne, tai tesiame.

    ; raide:            ; Jei raide.

      ; add al, 0x37    ; Pridedame 0x37, kad gautume ASCII simboli.
      ; call printChar  ; Kvieciame simbolio spausdinimo procedura.
      ; dec cl          ; Viena simboli atspausdinome, todel sumaziname skaitliuka.
      ; cmp cl, 0x00    ; Tikriname ar du simboliai atspausdinti.
      ; je pabaiga      ; Jei taip, tai baigiame proceduros darba.
      ; jmp tesinys     ; Jei ne, tai tesiame.

  ; pabaiga:

    ; ret               ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Proceduru kvieciamu is main proceduros
; realizacijos.
;------------------------------------------------

;------------------------------------------------
; Procedura skirta sumazinti pasikartojancio
; kodo naudojima.
;
; Cng reg: BX, AX, DX
;------------------------------------------------
tmpProcedure:

  mov bx, tmp_dd
  call read4Bytes

  ;Issivalome registrus.
  xor ax, ax
  xor dx, dx
  
  ;Pasiskaiciuojame loader inode.
  mov ax, word [tmp_dd+0x02]
  call calculateInode

  ;Nuskaitome Inode Table bloka (1024 baitu) (gali buti ne 0 bloku grupe)
  mov byte [number_of_sectors], 0x04
  call readBlock
  
  ret                   ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Procedura perskaitanti 4 baitus is atminties
; adresu 0x1000:AX.
;
; Cng reg: AX, SI
; In: AX, BX
; Out: nuskaityti 4 baitai i BX registre
;      nurodyta adresa.
;------------------------------------------------
read4Bytes:

  mov si, ax                ; Nusistatome offset'a.
  mov ax, word [es:si]      ; Nusiskaitome zodi i AX.
  mov word [bx+0x02], ax    ; Irasome pirma zodi.
  mov ax, word [es:si+0x02]
  mov word [bx], ax

  ret                   ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Procedura apskaiciuojanti kokiame bloke yra
; Inode Table ir kelintas inode toje lenteleje
; yra reikalingas.
;
; Cng reg: AX, DX
; In: AX
; Out: AX - Inode leneteles bloko numeris,
;      tmp_dd - inode numeris
;------------------------------------------------
calculateInode:

  div word [inodes_per_group+0x02]  ; AX esanti inode numeri daliname is inode skaiciaus
                                    ; esanciu vineoje grupeje.
  
  push dx                           ; Issisaugome liekana.
  
  mul word [blocks_per_group+0x02]  ; Dauginame is bloku skaiciaus grupeje.
  add ax, word [inode_table+0x02]   ; Pridedame kokiame bloke yra inode lentele,
                                    ; AX registre lieka inode lenetles bloko numeris.
  
  pop dx

  mov word [tmp_dd+0x02], dx        ; Liekana yra inode numeris lenteleje.

  ret                               ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Procedura perskaitanti viena sektoriu is
; apskaiciuoto bloko.
;
; Cng reg: AX, DX
; In: AX
; Out: sektorius ikeltas i atminti adresu 
;      0x1000:0x0000.
;------------------------------------------------
readBlock:

  xor bx, bx
  xor dx, dx
  
  
  mov bx, 0x01f8
  div bx
  mov byte [cylinder_number], al
  
  xor ax, ax
  mov ax, dx
  
  add ax, ax            ; Padvigubiname AX reiksme, nes 1024/512=2.
  mov dl, 0x3f          ; Viena galva atitinka 0x3f bloku.
  div dl                ; Daliname is 0x3f, kad apskaiciuotume head_number.
  add ah, 0x01          ; Pridedame 0x01, kad apskaiciuotume sector_number.
  
  mov byte [sector_number], ah
  mov byte [head_number], al
  call readSector
  
  ret                   ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Procedura skaitanti sektorius is usb.
;
; Cng reg: AX, ES, BX, CX, DX
; In: numberOfSectors, cylinderNumber,
;     sectorNumber, headNumber, bootDrive,
;     sector_to, read_to
; Out: sektorius ikeltas i atminti adresu 
;      sector_to:read_to.
;------------------------------------------------
readSector:

  mov ax, word [sector_to]        ; Sektorius skaitysime adresu sector_to:read_to.
  mov es, ax
  xor bx, bx
  mov bx, word [read_to]

  read:

    mov ah, 0x02                      ; Sektoriu skaitymo i atminti pertraukimas.
    mov al, byte [number_of_sectors]  ; Kiek sektoriu reikia perskaityti.
    mov ch, byte [cylinder_number]    ; Cilindro numeris.
    mov cl, byte [sector_number]      ; Sektoriaus numeris.
    mov dh, byte [head_number]        ; Galvutes numeris.
    mov dl, byte [boot_drive]         ; Irenginio numeris.
    int 0x13                          ; Pertraukimas.
    jc read                           ; Jeigu buvo klaida - bandome dar karta.
 
    ret                 ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Procedura atspausdinanti eilute ekrane.
;
; Cng reg: AL, SI
; In: SI - eilutes pradzios adresas.
; Out: ekrane atspausdinta eilute.
;------------------------------------------------
printString:

  nextChar:

    mov al, [si]  ; I AL ikrauname baita i kuri rodo SI.
    inc si        ; Didiname SI vienetu, kad SI rodytu i sekanti baita.

  or al, al       ; Tikriname ar AL yra 0'is (tai reikstu eilutes pabaiga).
  jz exitPrintString  ; Jei salyga tenkinama - baigiame darba.
  call printChar  ; Priesingu atveju - kvieciame simbolio spausdinimo procedura.

  jmp nextChar    ; Imsime kita simboli spausdinimui.

  exitPrintString:
  
    ret           ; Griztame i proceduros kvietimo vieta.

;------------------------------------------------
; Procedura atspausdinanti simboli ekrane.
;
; Cng reg: AH, BH, BL
; In: AL - simbolio  ASCII kodas.
; Out: ekrane atspausdintas simbolis.
;------------------------------------------------
printChar:

  mov ah, 0x0e  ; Simbolio isvedimo i ekrana pertraukimas.
  mov bh, 0x00  ; Puslapio numeris.
  mov bl, 0x07  ; Srifto spalvos kodas (0x07 - pilka).
  int 0x10      ; Pertraukimas.

  ret           ; Griztame i proceduros kvietimo vieta.
  
;----------
; Duomenys
;----------

; GDT duomenys
gdt_data:
; GDT null:                     ; Null deskriptorius.
	dd 0
	dd 0 

; GDT code:                     ; Code deskriptorius.
	dw 0FFFFh 			              ; limit low
	dw 0 				                  ; base low
	db 0 				                  ; base middle
	db 10011010b 			            ; access
	db 11001111b 			            ; granularity
	db 0 				                  ; base high

; GDT data:                     ; Data deskriptorius.
	dw 0FFFFh 			              ; limit low (Same as code)
	dw 0 				                  ; base low
	db 0 				                  ; base middle
	db 10010010b 			            ; access
	db 11001111b 			            ; granularity
	db 0				                  ; base high
end_of_gdt:

toc: 
	dw end_of_gdt - gdt_data - 1 	; limit (Size of GDT)
	dd gdt_data 			            ; base of GDT

; Kintamieji readSector procedurai.
boot_drive         db 0x00
number_of_sectors  db 0x01
cylinder_number    db 0x00
sector_number      db 0x00
head_number        db 0x00

; Informacija is SuperBlock.
block_size         dd 0x00000000
blocks_per_group   dd 0x00000000
inodes_per_group   dd 0x00000000

; Informacija is Group Descriptor Table.
inode_table        dd 0x00000000  ; Kokiame sektoriuje, nuo grupes pradzios yra Inode Table.

; Papildomi kintamieji kernel paieskai.
kernel_size   dd 0x00000000   
kernel_block  dd 0x00000000   

; Adresas, kur bus skaitoma informacija is laikmenos.
read_to       dw 0x0000
sector_to     dw 0x1000

; Pirmo bloko adreso pradzia Inode aprase.
offset_of     dw 0x0028

; Papildomas laikinas kintamasis.
tmp_dd        dd 0x00000000

; 13 ir 14 kernel'io failo blokai.
block_13      dd 0x00000000
block_14      dd 0x00000000

block_no      dw 0x0000

; Kintamieji ELF failo analizei.
p_offset      dd 0x00000000
p_vaddr       dd 0x00000000
p_filesz      dd 0x00000000

; Tekstine informacija.
stringStage   db 'Entering [Stage 2]...', 0x0d, 0x0a, 0x00
stringGDT     db 'Loading GDT...', 0x0d, 0x0a, 0x00
stringStack   db 'Creating Stack...', 0x0d, 0x0a, 0x00
stringA20     db 'Enabling A20 Mode...', 0x0d, 0x0a, 0x00
stringNMI     db 'Disabling NMI...', 0x0d, 0x0a, 0x00
stringPMode   db 'Entering Protected Mode...', 0x0d, 0x0a, 0x00

; Reikalingas printHEX prodecurai.
; tmp           db 0x00

;------------------------------------------------

[bits 32]

Stage3:

  prepareSegments:
  
    xor eax, eax
    mov	ax, 0x10
    mov	ds, ax
    mov	es, ax
    mov fs, ax
    mov gs, ax
    mov	ss, ax
    mov	esp, 0x90000
  
  copyImage:

    xor eax, eax
    xor ebx, ebx
    mov	ax, word [block_no]
  	movzx	ebx, word [block_size+0x02]
  	mul	ebx
  	mov	ebx, 4
  	div	ebx
   	cld
   	mov esi, 0x20000
   	mov	edi, 0x100000
   	mov	ecx, eax
   	rep	movsd
  
  prepareELF:
  
    xor eax, eax
    mov ax, word [0x10001c]
    add eax, 0x100000
    
    add eax, 0x4
    xor ebx, ebx
    mov ebx, dword [eax]
    mov dword [p_offset], ebx
    
    add eax, 0x4
    xor ebx, ebx
    mov ebx, dword [eax]
    mov dword [p_vaddr], ebx
    
    add eax, 0x8
    xor ebx, ebx
    mov ebx, dword [eax]
    mov dword [p_filesz], ebx
    
    xor eax, eax
    mov eax, dword [p_offset]
    add eax, dword [p_vaddr]
    mov dword [p_offset], eax
    
    xor eax, eax
    xor ebx, ebx
    mov	ax, word [0x0001]
    mov	ebx, dword [p_filesz]
  	mul	ebx
  	mov	ebx, 4
  	div	ebx
   	cld
   	mov esi, dword [p_offset]
   	mov	edi, dword [p_vaddr]
   	mov	ecx, eax
   	rep	movsd
  
  executeELF:
  
    call dword [p_vaddr]
	
		cli
		hlt
  